using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using FarseerPhysics.DebugViews;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Factories;

namespace Doodleberg
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        Texture2D tex_background;

        DebugViewXNA debug;

        public enum GameState { MENU, PLAY, EDIT }
        private GameState gameState;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            gameState = GameState.EDIT;

            Global.gameProperties.content = Content;
            Global.gameProperties.controlManager = new ControlManager();
            Global.gameProperties.lineInput = new LineInputManager();

            //Farseer debugview
            debug = new DebugViewXNA(Global.level.phyWorld);
            debug.DefaultShapeColor = Color.White;
            debug.SleepingShapeColor = Color.LightGray;

            //Load first level
            Global.level.advanceLevel();

            graphics.PreferredBackBufferWidth = 1024;
            graphics.PreferredBackBufferHeight = 768;
            graphics.ApplyChanges();
            //graphics.ToggleFullScreen();

            this.IsMouseVisible = true;

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            Global.level.loadContent();

            debug.LoadContent(GraphicsDevice, Content);

            tex_background = Content.Load<Texture2D>("background");
            Global.gameProperties.font = Content.Load<SpriteFont>("font");
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            if (this.IsActive)
            {
                Global.gameProperties.controlManager.update(gameTime);

                switch (gameState)
                {
                    case GameState.PLAY:
                        if (!Global.level.isRunning)
                            Global.gameProperties.lineInput.update(gameTime);
                        else
                            Global.level.update(gameTime);

                        //Level skip cheat
                        if (Global.gameProperties.controlManager.getControl(ControlManager.LEVELSKIP))
                            Global.level.advanceLevel();

                        //Start/stop running
                        if (Global.gameProperties.controlManager.getControl(ControlManager.TOGGLERUN))
                        {
                            Global.level.isRunning = !Global.level.isRunning;
                            if (!Global.level.isRunning)
                                Global.level.reset();
                        }

                        //Next level
                        if (Global.gameProperties.victory &&
                            Global.gameProperties.controlManager.getControl(ControlManager.ADVANCELEVEL))
                            Global.level.advanceLevel();
                        break;


                    case GameState.EDIT:
                        Global.editor.update(gameTime);
                        break;


                    case GameState.MENU:

                        break;
                }
            }

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);

            //Draw background
            for (int x = 0; x <= GraphicsDevice.Viewport.Width / tex_background.Width; x++)
            {
                for (int y = 0; y <= GraphicsDevice.Viewport.Height / tex_background.Height; y++)
                {
                    spriteBatch.Draw(
                        tex_background,
                        new Vector2(x * tex_background.Width, y * tex_background.Height),
                        null,
                        Color.White,
                        0.0f,
                        Vector2.Zero,
                        Vector2.One,
                        SpriteEffects.None,
                        1.0f);
                }
            }

            switch (gameState)
            {
                case GameState.PLAY:
                    Global.gameProperties.lineInput.draw(spriteBatch);
                    Global.level.draw(spriteBatch);

                    //Victory message
                    if (Global.gameProperties.victory)
                    {
                        spriteBatch.DrawString(
                            Global.gameProperties.font,
                            "You win!",
                            new Vector2(400.0f, 400.0f),
                            Color.Black);
                        spriteBatch.DrawString(
                            Global.gameProperties.font,
                            "Press Return to go to the next level",
                            new Vector2(400.0f, 420.0f),
                            Color.Black);
                    }

                    //Ink left
                    spriteBatch.DrawString(
                        Global.gameProperties.font,
                        Global.gameProperties.currentInk + "/" + Global.maxInk,
                        new Vector2(10, 100),
                        Color.Black);
                    break;


                case GameState.EDIT:
                    Global.editor.draw(spriteBatch);
                    Global.level.draw(spriteBatch);
                    break;


                case GameState.MENU:

                    break;
            }

            spriteBatch.End();

            Matrix proj = Matrix.CreateOrthographicOffCenter(0,
                graphics.PreferredBackBufferWidth / Global.farseer_conversion,
                graphics.PreferredBackBufferHeight / Global.farseer_conversion, 0, -1, 1);
            Matrix view = Matrix.Identity;
            debug.RenderDebugData(ref proj, ref view);

            base.Draw(gameTime);
        }
    }
}
